// chris 19 Dec 2011
package com.chrishobson.maths;

/**
 * A class which holds an angle, that angle may be degrees or radians
 * and is seamlessly converted between the two as required. The sin and cos
 * of the angle are cached the first time they are accessed.
 * <p>
 * An angle can be copied (Become another angle), and can also be changed. The
 * angle can be accessed in degrees or radians as the mood takes you.
 * @author clh
 *
 */

public class Angle {
  
  /**
   * Creates the angle.
   * @param a_Type
   * Its type, degrees or radians
   * @param a_Angle
   * The angle
   */
  public Angle(Type a_Type, double a_Angle) {
    Set(a_Type, a_Angle);
  }
  
  /**
   * Make an Angle from another, makes a copy.
   * @param a_Copy
   */
  public Angle(Angle a_Copy) {
    Become(a_Copy);
  }

  /**
   * Changes this angle to be the same as another
   * @param a_Copy
   * @return This angle
   */
  public Angle Become(Angle a_Copy) {
    m_Degrees = a_Copy.m_Degrees;
    m_Radians = a_Copy.m_Radians;
    m_Sin = a_Copy.m_Sin;
    m_Cos = a_Copy.m_Cos;
    return this;
  }
  
  /**
   * Change the angle
   * @param a_Type
   * @param a_Angle
   */
  public void Set(Type a_Type, double a_Angle) {
    if(a_Type == Type.DEGREES) {
      m_Degrees = a_Angle;
      m_Radians = Math.toRadians(a_Angle);
    } else {
      m_Degrees = Math.toDegrees(a_Angle);
      m_Radians = a_Angle;
    }
    m_Cos = m_Sin = -3;
  }

  /**
   * Access in degrees.
   * @return
   */
  public double Degrees() {
    return m_Degrees;
  }

  /**
   * Access in radians
   * @return
   */
  public double Radians() {
    return m_Radians;
  }
  
  /**
   * Obtain the cosine of the angle
   * @return
   */
  public double Cos()
  {
    return m_Cos < -1 ? (m_Cos = Math.cos(m_Radians)) : m_Cos;
  }
  /**
   * Obtain the sine of the angle
   * @return
   */
  public double Sin()
  {
    return m_Sin < -1 ? (m_Sin = Math.sin(m_Radians)) : m_Sin;
  }

  private double m_Degrees;
  private double m_Radians;
  private double m_Cos;
  private double m_Sin;
  
  enum Type {
    DEGREES, RADIANS;
  }
}
